from typing import Dict, Any, List, Optional
from fastapi import APIRouter, Depends, HTTPException
import time
import psutil
import os
import asyncio
from datetime import datetime, timedelta

from app.database import db_manager
from app.redis_client import redis_client
from app.utils.logging import get_logger
from app.config import settings

# 创建路由器
router = APIRouter(prefix="/monitoring", tags=["monitoring"])

# 创建日志对象
logger = get_logger(__name__)

# 缓存命中统计
cache_stats = {
    "hits": 0,
    "misses": 0,
    "total_requests": 0,
    "hit_rate": 0.0,
    "last_reset": datetime.now().isoformat(),
}

def increment_cache_hit():
    """增加缓存命中计数"""
    cache_stats["hits"] += 1
    cache_stats["total_requests"] += 1
    if cache_stats["total_requests"] > 0:
        cache_stats["hit_rate"] = cache_stats["hits"] / cache_stats["total_requests"] * 100

def increment_cache_miss():
    """增加缓存未命中计数"""
    cache_stats["misses"] += 1
    cache_stats["total_requests"] += 1
    if cache_stats["total_requests"] > 0:
        cache_stats["hit_rate"] = cache_stats["hits"] / cache_stats["total_requests"] * 100

def reset_cache_stats():
    """重置缓存统计"""
    cache_stats["hits"] = 0
    cache_stats["misses"] = 0
    cache_stats["total_requests"] = 0
    cache_stats["hit_rate"] = 0.0
    cache_stats["last_reset"] = datetime.now().isoformat()

async def get_system_metrics() -> Dict[str, Any]:
    """获取系统指标"""
    cpu_percent = psutil.cpu_percent(interval=0.5)
    memory = psutil.virtual_memory()
    disk = psutil.disk_usage('/')
    
    return {
        "cpu": {
            "percent": cpu_percent,
            "cores": psutil.cpu_count(logical=True),
            "physical_cores": psutil.cpu_count(logical=False),
        },
        "memory": {
            "total_gb": round(memory.total / (1024 ** 3), 2),
            "available_gb": round(memory.available / (1024 ** 3), 2),
            "used_gb": round(memory.used / (1024 ** 3), 2),
            "percent": memory.percent,
        },
        "disk": {
            "total_gb": round(disk.total / (1024 ** 3), 2),
            "used_gb": round(disk.used / (1024 ** 3), 2),
            "free_gb": round(disk.free / (1024 ** 3), 2),
            "percent": disk.percent,
        },
        "process": {
            "pid": os.getpid(),
            "memory_mb": round(psutil.Process(os.getpid()).memory_info().rss / (1024 ** 2), 2),
            "cpu_percent": psutil.Process(os.getpid()).cpu_percent(interval=0.5),
            "threads": len(psutil.Process(os.getpid()).threads()),
        }
    }

async def get_database_metrics() -> Dict[str, Any]:
    """获取数据库指标"""
    if not db_manager.engine or not db_manager._is_connected:
        return {"status": "not_connected"}
    
    try:
        return {
            "status": "connected",
            "last_heartbeat": datetime.fromtimestamp(db_manager._last_heartbeat).isoformat() if db_manager._last_heartbeat else None,
            "reconnect_attempts": db_manager._reconnect_attempts,
            "pool": {
                "size": db_manager.engine.pool.size(),
                "checkedin": db_manager.engine.pool.checkedin(),
                "overflow": db_manager.engine.pool.overflow(),
                "checkedout": db_manager.engine.pool.checkedout(),
            }
        }
    except Exception as e:
        logger.error(f"Error getting database metrics: {str(e)}")
        return {"status": "error", "error": str(e)}

async def get_redis_metrics() -> Dict[str, Any]:
    """获取Redis指标"""
    if not redis_client._redis or not redis_client._is_connected:
        return {"status": "not_connected"}
    
    try:
        # 获取Redis信息
        info = await redis_client._redis.info()
        
        return {
            "status": "connected",
            "version": info.get("redis_version", "unknown"),
            "clients": {
                "connected": info.get("connected_clients", 0),
                "blocked": info.get("blocked_clients", 0),
            },
            "memory": {
                "used": info.get("used_memory_human", "unknown"),
                "peak": info.get("used_memory_peak_human", "unknown"),
                "fragmentation_ratio": info.get("mem_fragmentation_ratio", 0),
            },
            "stats": {
                "total_commands_processed": info.get("total_commands_processed", 0),
                "total_connections_received": info.get("total_connections_received", 0),
                "expired_keys": info.get("expired_keys", 0),
                "evicted_keys": info.get("evicted_keys", 0),
                "keyspace_hits": info.get("keyspace_hits", 0),
                "keyspace_misses": info.get("keyspace_misses", 0),
                "keyspace_hit_rate": round(
                    info.get("keyspace_hits", 0) / 
                    (info.get("keyspace_hits", 0) + info.get("keyspace_misses", 1)) * 100, 2
                ) if info.get("keyspace_hits", 0) + info.get("keyspace_misses", 0) > 0 else 0,
            },
            "cache": cache_stats,
        }
    except Exception as e:
        logger.error(f"Error getting Redis metrics: {str(e)}")
        return {"status": "error", "error": str(e)}

@router.get("/system")
async def system_metrics():
    """系统指标接口"""
    return await get_system_metrics()

@router.get("/database")
async def database_metrics():
    """数据库指标接口"""
    return await get_database_metrics()

@router.get("/redis")
async def redis_metrics():
    """Redis指标接口"""
    return await get_redis_metrics()

@router.get("/cache/stats")
async def cache_statistics():
    """缓存统计接口"""
    return cache_stats

@router.post("/cache/reset")
async def reset_cache_statistics():
    """重置缓存统计接口"""
    reset_cache_stats()
    return {"message": "Cache statistics reset successfully", "stats": cache_stats}

@router.get("/all")
async def all_metrics():
    """所有监控指标接口"""
    start_time = time.time()
    
    # 并行获取所有指标
    system = await get_system_metrics()
    database = await get_database_metrics()
    redis = await get_redis_metrics()
    
    # 计算总耗时
    duration = time.time() - start_time
    
    return {
        "timestamp": datetime.now().isoformat(),
        "response_time_ms": round(duration * 1000, 2),
        "app_name": settings.app_name,
        "system": system,
        "database": database,
        "redis": redis,
    }
